import math
from mathutils import Vector
import starfield
import random

class Entity:
	def __init__(self, location = Vector([0.0, 0.0, 0.0])):
		self.location = location
		self.velocity = Vector([0.0, 0.0, 0.0])
		self.mass = 1.0
		self.speed = 1.0
		
		
		self.G = starfield.GRAVITY
		
		# Orbit variables
		self.mass = 5000
		self.last_update = 0
		self.arrival_time = 0
		
		#STATES
			#0 = not moving
			#1 = moving to a target
			#2 = orbiting a target
			
		self.state = 0
		
		# used in orbits #
		self.rotation = random.choice([-1, 1])
	
	# OUT OF DATE #
	def update(self, time):
		
		# Entity is not moving, do nothing
		if self.state == 0:
			pass
			
		# Entity is moving torward a target
		elif self.state == 1:
			delta_time = time - self.last_update
			if self.arrival_time > delta_time + self.last_update:
				self.location = self.location + self.velocity * delta_time
				self.state = 1
			elif self.arrival_time > self.last_update:
				self.location = self.location + self.velocity * (self.arrival_time - self.last_update)
				self.state = 1
			else:
				self.stop()
			
		# Entity is orbiting a target
		elif self.state == 2:
			# Calculate each component for the new location #
			x = self.orbital_rad * math.cos(((self.orbital_start - time)/self.orbital_per) * (2 * math.pi) + self.orbital_angleOffset)
			y = self.orbital_rad * math.sin(((self.orbital_start - time)/self.orbital_per) * (2 * math.pi) + self.orbital_angleOffset)
			z = self.location.z

			# Set new location #
			self.location = Vector([x, y, z]) + self.target.location
			
			# We just updated #
			self.last_update = time
			
		# Invalid state
		else: 
			pass
		
		self.last_update = time
	
	# target is a Vector #
	def moveTo(self, target, time):
		if type(target) == list:
			target = Vector(target)
		# The vector to the object
		vecTo = target - self.location
		distance = vecTo.magnitude
		vecTo = vecTo.normalize()
		
		# Now let's set the speed
		self.velocity = vecTo * self.speed
		
		# Set state
		self.state = 1
		
		# Remember when we started
		self.start_time = time
		
		# When will we arrive?
		self.arrival_time = distance/self.speed + self.start_time
		self.last_update = self.start_time
		
		self.state = 1
		self.target = target
		
		print("SHIP: ",self.id," departing, arrives at: ", self.arrival_time)
		
		return self.arrival_time
		
	# returns orbital period or -1 if target cannot be orbited#
	def orbit(self, target, time):
	
		# make sure the target can be orbited #
		if target.rotation and target.mass:
			self.target = target
			# remember starting time #
			self.orbital_start = time
			self.last_update = time
			
			# set state #
			self.state = 2
			
			vecTo = (target.location - self.location)
			# orbital radius #
			self.orbital_rad = vecTo.magnitude
			vecTan = vecTo.normalize().rotate(Vector([0.0, 0.0, target.rotation]), 1/2 * math.pi)
			
			# orbital radius #
			# orbital direction (-1, 1) #
			self.orbital_dir = target.rotation
			# orbital mu #
			self.orbital_mu = self.G * (self.mass + target.mass)
			# orbital speed #
			self.orbital_spe = math.sqrt(self.orbital_mu)
			# orbital velocity #
			self.orbital_vel = self.orbital_spe * vecTan
			# orbital period #
			self.orbital_per = 2 * math.pi * math.sqrt((self.orbital_rad * self.orbital_rad * self.orbital_rad) / self.orbital_mu)
			
			
			self.orbital_offset = self.target.location
			self.orbital_angleOffset = math.atan2((self.location - target.location).normalize().y, (self.location - target.location).normalize().x) 
			
			return self.orbital_per
		
		else:
			return -1
			
	def stop(self):
		self.velocity = Vector([0, 0, 0])
		self.state = 0
